package edu.jhu.cs.oose.scheduleit.backingbeans;

import java.util.ArrayList;
import java.util.List;

import javax.faces.context.FacesContext;

import edu.jhu.cs.oose.scheduleit.services.GroupService;
import edu.jhu.cs.oose.scheduleit.services.UserService;
import edu.jhu.cs.oose.scheduleit.services.impl.DataBaseException;
import edu.jhu.cs.oose.scheduleit.util.Attribute;
import edu.jhu.cs.oose.scheduleit.util.GroupAttributeKind;
import edu.jhu.cs.oose.scheduleit.util.GroupDecorater;
import edu.jhu.cs.oose.scheduleit.util.JoinRule;
import edu.jhu.cs.oose.scheduleit.util.JoinStatus;
import edu.jhu.cs.oose.scheduleit.vo.Group;
import edu.jhu.cs.oose.scheduleit.vo.User;
import edu.jhu.cs.oose.scheduleit.vo.UserInfo;

/**
 * the backing bean used to deal with all functions related to 'Group' feature.
 * @author oose_group2
 *
 */
public class GroupBackingBean {
	/**
	 * used to track which group user is viewing
	 */
	private GroupDecorater selectedGroup;
	/**
	 * used to save all the groups a user own and joined.
	 */
	private List<GroupDecorater> groupList=null;
	/**
	 * group service reference
	 */
	private GroupService groupService;
	/**
	 * user service reference
	 */
	private UserService userService;
	/**
	 * save as the current login user
	 */
	private User host;
	/**
	 * used to save description attribute when creating group.
	 */
	private String description;
	/**
	 * used to save topic attribute when creating group.
	 */
	private String topic;
	/**
	 * used to save join rule attribute when creating group.
	 */
	private boolean joinRule;
	/**
	 * render the requester list of selected group.
	 */
	private List<UserInfo> requestList;
	/**
	 * getter of requestList
	 * @return
	 */
	public List<UserInfo> getRequestList() {
		return requestList;
	}
	/**
	 * setter of requestList.
	 * @param requestList
	 */
	public void setRequestList(List<UserInfo> requestList) {
		this.requestList = requestList;
	}
	/**
	 * constructor of GroupBackingBean.
	 */
	public GroupBackingBean() {
		FacesContext context = FacesContext.getCurrentInstance();
		UserBackingBean ubb = (UserBackingBean) context.getExternalContext()
		.getSessionMap().get("userBackingBean");
		this.host = ubb.getLogin_user();
	}
	/**
	 * create a group according to user input.
	 * @return JSF direction string.
	 */
	public String createGroup() {
		Attribute attribute = new Attribute();
		attribute.put(GroupAttributeKind.clicks, 0);
		attribute.put(GroupAttributeKind.description, this.description);
		attribute.put(GroupAttributeKind.topic, this.topic);
		if (this.joinRule == true)
			attribute.put(GroupAttributeKind.joinRule, JoinRule.PRIVATE);
		else
			attribute.put(GroupAttributeKind.joinRule, JoinRule.PUBLIC);
		if (this.host == null) {
			FacesContext context = FacesContext.getCurrentInstance();
			UserBackingBean ubb = (UserBackingBean) context
			.getExternalContext().getSessionMap()
			.get("userBackingBean");
			this.host = ubb.getLogin_user();
		}
		try {
			Group newGroup = this.groupService
			.createGroup(this.host, attribute);
			this.topic = null;
			this.description = null;
			this.joinRule = false;
			if (newGroup != null) {
				return "correct";
			} else
				return "failure";
		} catch (DataBaseException e) {
			e.printStackTrace();
			return "failure";
		}

	}
	/**
	 * setter of selectedGroup
	 * @param selectedGroup
	 */
	public void setSelectedGroup(GroupDecorater selectedGroup) {
		this.selectedGroup = selectedGroup;
	}
	/**
	 * getter of selectedGroup
	 * @return
	 */
	public GroupDecorater getSelectedGroup() {
		return selectedGroup;
	}
	/**
	 * setter of groupList
	 * @param groupList
	 */
	public void setGroupList(List<GroupDecorater> groupList) {
		this.groupList = groupList;
	}
	/**
	 * getter of groupList
	 * @return
	 */
	public List<GroupDecorater> getGroupList() {
		this.groupList = new ArrayList<GroupDecorater>();
		try {

			List<Group> tmpResult = null;
			for(JoinStatus status: JoinStatus.values()){
				if (status == JoinStatus.DENIED)
					continue;
				tmpResult= this.userService.getGroup(this.host,
						status, 0, Integer.MAX_VALUE);
				for (Group g :tmpResult){
					List<UserInfo> joinedUsers = groupService.getUser(g, JoinStatus.JOINED, 0, 0);
					int size = joinedUsers.size();
					boolean applying =false;
					List<UserInfo> applyingUsers = null;
					if (status == JoinStatus.OWNED){
						applyingUsers = groupService.getUser(g, JoinStatus.APPLIED, 0, 0);
						applying = applyingUsers.size() > 0; 
					}else if (status == JoinStatus.APPLIED){
						List<UserInfo> tmp = groupService.getUser(g, JoinStatus.APPLIED, 0, 0);
						if (!tmp.contains(this.host.getUserInfo())){
							status = JoinStatus.DENIED;
						}
					}

					this.groupList.add(new GroupDecorater(g,joinedUsers,size, status, applying,applyingUsers,this.host));
					System.out.println("!!Topic;"+new GroupDecorater(g,joinedUsers,size, status, applying,applyingUsers,this.host).getStatus());
				}

			}

		} catch (DataBaseException e) {
			e.printStackTrace();
		}
		return this.groupList;
	}
	/**
	 * setter of groupService.
	 * @param groupService
	 */
	public void setGroupService(GroupService groupService) {
		this.groupService = groupService;
	}
	/**
	 * getter of groupService.
	 * @return
	 */
	public GroupService getGroupService() {
		return groupService;
	}
	/**
	 * setter of host
	 * @param host
	 */
	public void setHost(User host) {
		this.host = host;
	}
	/**
	 * getter of host
	 * @return
	 */
	public User getHost() {
		return host;
	}
	/**
	 * setter of description
	 * @param description
	 */
	public void setDescription(String description) {
		this.description = description;
	}
	/**
	 * getter of description
	 * @return
	 */
	public String getDescription() {
		return description;
	}
	/**
	 * setter of topic
	 * @param topic
	 */
	public void setTopic(String topic) {
		this.topic = topic;
	}
	/**
	 * getter of topic
	 * @return
	 */
	public String getTopic() {
		return topic;
	}
	/**
	 * setter of joinRule.
	 * @param joinRule
	 */
	public void setJoinRule(boolean joinRule) {
		this.joinRule = joinRule;
	}
	/**
	 * getter of joinRule.
	 * @return
	 */
	public boolean isJoinRule() {
		return joinRule;
	}
	/**
	 * method to respond to view group schedule.
	 * @return JSF direction string
	 */
	public String displayGroup() {
		FacesContext context = FacesContext.getCurrentInstance();
		int groupid = Integer.parseInt(context.getExternalContext().getRequestParameterMap().get("groupId"));
		for(GroupDecorater group:this.groupList){
			if(group.getId()==groupid && (group.getStatus() == JoinStatus.OWNED || group.getStatus() == JoinStatus.JOINED)){
				try {
					ScheduleBackingBean sbb = (ScheduleBackingBean)context.getExternalContext().getSessionMap().get("scheduleBackingBean");
					sbb.initCalendar(group.getSchedule(), false);
					return "viewSchedule";
				} catch (DataBaseException e) {
					return null;
				}
			}
		}
		return null;
	}
	/**
	 * setter of userService.
	 * @param userService
	 */
	public void setUserService(UserService userService) {
		this.userService = userService;
	}
	/**
	 * getter of userService.
	 * @return
	 */
	public UserService getUserService() {
		return userService;
	}
	/**
	 * method to respond to join group command.
	 * @throws DataBaseException
	 */
	public void joinGroup() throws DataBaseException{
		FacesContext context = FacesContext.getCurrentInstance();
		int groupid = Integer.parseInt(context.getExternalContext().getRequestParameterMap().get("groupId"));
		SearchBackingBean srbb = (SearchBackingBean)context.getExternalContext().getSessionMap().get("searchBackingBean");
		for(Group group:srbb.getGroups()){
			if(group.getId()==groupid){
				if(this.getGroupList().contains(group)){
					//Do something error message here
				} else {
					this.groupService.joinGroup(group, this.host);
					//this.getGroupList().add(group);
				}
				break;
			}
		}
	}
	/**
	 * method to respond to check requester list command
	 * @return JSF direction string
	 * @throws DataBaseException
	 */
	public String checkRequest() throws DataBaseException{
		FacesContext context = FacesContext.getCurrentInstance();
		int groupid = Integer.parseInt(context.getExternalContext().getRequestParameterMap().get("groupId"));
		for(GroupDecorater groupDec:this.groupList){
			if(groupDec.getId()==groupid){
				this.selectedGroup = groupDec;
				this.requestList = groupDec.getApplyingUsers();
				break;
			}
		}
		return "checkRequest";
	}
	/**
	 * method to respond to quit or dismiss group command.
	 * @throws DataBaseException
	 */
	public void deleteGroup() throws DataBaseException{
		FacesContext context = FacesContext.getCurrentInstance();
		int groupid = Integer.parseInt(context.getExternalContext().getRequestParameterMap().get("groupId"));
		for(GroupDecorater groupDec:this.groupList){
			if(groupDec.getId()==groupid){
				this.groupService.quitGroup(groupDec.getGroup(), this.host);
				break;
			}
		}
	}
	/**
	 * respond to accept a requester by group owner
	 * @throws DataBaseException
	 */
	public void acceptRequest () throws DataBaseException{
		FacesContext context = FacesContext.getCurrentInstance();
		String userEmail = context.getExternalContext().getRequestParameterMap().get("userEmail");
		User user = this.userService.getUser(userEmail);
		this.groupService.accept(this.selectedGroup.getGroup(), user);
		this.requestList.remove(user.getUserInfo());
	}
	/**
	 * respond to reject a requester by group owner
	 * @throws DataBaseException
	 */
	public void rejectRequest () throws DataBaseException {
		FacesContext context = FacesContext.getCurrentInstance();
		String userEmail = context.getExternalContext().getRequestParameterMap().get("userEmail");
		User user = this.userService.getUser(userEmail);
		this.groupService.reject(this.selectedGroup.getGroup(), user);
		this.requestList.remove(user.getUserInfo());
	}
}
